//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package user_app_api_serv

import (
	"context"
	"time"

	"atomgit.com/openlinksaas-org/api-server/dao"
	"atomgit.com/openlinksaas-org/api-server/dao/user_dao"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/user_app_api"
	"go.mongodb.org/mongo-driver/mongo"
)

type UserAppApi struct {
	user_app_api.UnimplementedUserAppApiServer
}

func (apiImpl *UserAppApi) AddApp(ctx context.Context, req *user_app_api.AddAppRequest) (*user_app_api.AddAppResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &user_app_api.AddAppResponse{
			Code:   user_app_api.AddAppResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}

	nowTime := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		exist, err := user_dao.UserAppDao.Exist(sessCtx, sessionItem.UserId, req.AppId)
		if err != nil {
			return nil, err
		}
		if exist {
			err = user_dao.UserAppDao.UpdateTimeStamp(sessCtx, sessionItem.UserId, req.AppId, nowTime)
			if err != nil {
				return nil, err
			}
		} else {
			err = user_dao.UserAppDao.Insert(sessCtx, &user_dao.UserAppDbItem{
				UserId:    sessionItem.UserId,
				AppId:     req.AppId,
				TimeStamp: nowTime,
			})
			if err != nil {
				return nil, err
			}
		}
		return &user_app_api.AddAppResponse{
			Code: user_app_api.AddAppResponse_CODE_OK,
		}, nil
	})

	if err != nil {
		return nil, err
	}
	return ret.(*user_app_api.AddAppResponse), nil
}

func (apiImpl *UserAppApi) ListApp(ctx context.Context, req *user_app_api.ListAppRequest) (*user_app_api.ListAppResponse, error) {
	emptyList := []string{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &user_app_api.ListAppResponse{
			Code:      user_app_api.ListAppResponse_CODE_WRONG_SESSION,
			ErrMsg:    "会话不存在",
			AppIdList: emptyList,
		}, nil
	}

	appItemList, err := user_dao.UserAppDao.List(ctx, sessionItem.UserId)
	if err != nil {
		return nil, err
	}
	appIdList := []string{}
	for _, appItem := range appItemList {
		appIdList = append(appIdList, appItem.AppId)
	}
	return &user_app_api.ListAppResponse{
		Code:      user_app_api.ListAppResponse_CODE_OK,
		AppIdList: appIdList,
	}, nil
}

func (apiImpl *UserAppApi) SetTop(ctx context.Context, req *user_app_api.SetTopRequest) (*user_app_api.SetTopResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &user_app_api.SetTopResponse{
			Code:   user_app_api.SetTopResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}

	exist, err := user_dao.UserAppDao.Exist(ctx, sessionItem.UserId, req.AppId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &user_app_api.SetTopResponse{
			Code:   user_app_api.SetTopResponse_CODE_NO_APP,
			ErrMsg: "微应用记录不存在",
		}, nil
	}

	nowTime := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = user_dao.UserAppDao.UpdateTimeStamp(sessCtx, sessionItem.UserId, req.AppId, nowTime)
		if err != nil {
			return nil, err
		}
		return &user_app_api.SetTopResponse{
			Code: user_app_api.SetTopResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*user_app_api.SetTopResponse), nil
}

func (apiImpl *UserAppApi) RemoveApp(ctx context.Context, req *user_app_api.RemoveAppRequest) (*user_app_api.RemoveAppResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &user_app_api.RemoveAppResponse{
			Code:   user_app_api.RemoveAppResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}

	exist, err := user_dao.UserAppDao.Exist(ctx, sessionItem.UserId, req.AppId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &user_app_api.RemoveAppResponse{
			Code: user_app_api.RemoveAppResponse_CODE_OK,
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = user_dao.UserAppDao.Remove(sessCtx, sessionItem.UserId, req.AppId)
		if err != nil {
			return nil, err
		}
		return &user_app_api.RemoveAppResponse{
			Code: user_app_api.RemoveAppResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*user_app_api.RemoveAppResponse), nil
}
